package parser

import (
	"fmt"
	"strings"
)

var (
	pkg = `package entity
import (
	"errors"
	. "data/datatype"
)

type %s struct {
	ObjectType int
	%s
	%s
`
	gettype = `
//获取类型
func (obj *%s) Type(p string) (int, string, error) {
	switch p {
%s
	default:
		%s
	}
}
`
	typecase = `
	case "%s":
		return %s, "%s", nil
`
	setfunc = `
//通过属性名设置值
func (obj *%s) Set(p string, v interface{}) error {
	switch p {
%s
	default:
		%s
	}

	return nil
}
`
	setcase = `
	case "%s":
		val,ok := v.(%s)
		if ok {
			obj.Set%s(val)
		} else {
			return errors.New("Set(%s) value type mismatch")
		}
`
	getfunc = `
//通过属性名获取值
func (obj *%s) Get(p string) (val interface{}, err error) {
	switch p {
%s
	default:
		%s
	}
}
`
	getcase = `
	case "%s":
		return obj.%s, nil
`

	publicfunc = `
//是否需要同步到其它客户端
func (obj *%s) IsPublic(p string) bool {
	switch p {
		%s
	default:
		%s
	}
}
`

	privatefunc = `
//是否需要同步到自己的客户端
func (obj *%s) IsPrivate(p string) bool {
	switch p {
		%s
	default:
		%s
	}
}
`
	savefunc = `
//是否需要存档
func (obj *%s) IsSave(p string) bool {
	switch p {
		%s
	default:
		%s
	}
}
`
	deffunc = `
//脏标志(数据保存用)
func (obj *%s) setDirty(p string, v interface{}) {
	obj.mdirty[p] = v
}

func (obj *%s) GetDirty() map[string]interface{} {

	return obj.mdirty
}

func (obj *%s) ClearDirty() {
	for k := range obj.mdirty {
		delete(obj.mdirty, k)
	}
}

//修改标志(数据同步用)
func (obj *%s) setModify(p string, v interface{}) {
	obj.mmodify[p] = v
}

func (obj *%s) GetModify() map[string]interface{} {
	return obj.mmodify
}

func (obj *%s) ClearModify() {
	for k := range obj.mmodify {
		delete(obj.mmodify, k)
	}
}

`
)

func createCase(val map[string]string) string {
	s := `
	case "%s":
		return true
`
	o := ""
	for _, v := range val {
		o += fmt.Sprintf(s, v)
	}

	return o
}

func (obj *Object) CreateObj() string {
	//package

	basepro := ""
	if obj.Base == "" {
		basepro = `
	mdirty 	map[string]interface{}
	mmodify map[string]interface{}
`
	}

	rec := `
	//表格定义`
	for _, r := range obj.Records {
		rec += fmt.Sprintf(`
	%s_r %s%s //%s`, strings.ToLower(r.Name), obj.Name, r.Name, r.Comment)
	}

	o := fmt.Sprintf(pkg, obj.Name, obj.Base, basepro)

	public := make(map[string]string, len(obj.Propertys))
	private := make(map[string]string, len(obj.Propertys))
	save := make(map[string]string, len(obj.Propertys))
	stype := ""
	setprop := ""
	getprop := ""

	//struct property
	for _, p := range obj.Propertys {
		sp := fmt.Sprintf("	%s %s //%s\n", strings.ToLower(p.Name), p.Type, p.Comment)
		o += sp
		if strings.Index(p.Public, "self") > -1 {
			public[p.Name] = p.Name
		}
		if strings.Index(p.Public, "other") > -1 {
			private[p.Name] = p.Name
		}

		if strings.Index(p.Save, "true") > -1 {
			save[p.Name] = p.Name
		}
		stype += fmt.Sprintf(typecase, p.Name, "DT_"+strings.ToUpper(p.Type), p.Type)
		setprop += fmt.Sprintf(setcase, p.Name, p.Type, p.Name, p.Name)
		getprop += fmt.Sprintf(getcase, p.Name, strings.ToLower(p.Name))
	}

	o += rec + `
}`
	//Type()
	sdefault := `return DT_NONE, "", errors.New("Type(" + p + ") property not found")`
	if obj.Base != "" {
		sdefault = fmt.Sprintf("return obj.%s.Type(p)", obj.Base)
	}
	o += fmt.Sprintf(gettype, obj.Name, stype, sdefault)
	//Set(p,v)
	sdefault = `return errors.New("Set(" + p + ") property not found")`
	if obj.Base != "" {
		sdefault = fmt.Sprintf("obj.%s.Set(p, v)", obj.Base)
	}
	o += fmt.Sprintf(setfunc, obj.Name, setprop, sdefault)
	//Get(p)
	sdefault = `return nil, errors.New("Get(" + p + ") property not found")`
	if obj.Base != "" {
		sdefault = fmt.Sprintf("return obj.%s.Get(p)", obj.Base)
	}
	o += fmt.Sprintf(getfunc, obj.Name, getprop, sdefault)
	//IsPublic
	sdefault = `return false`
	if obj.Base != "" {
		sdefault = fmt.Sprintf("return obj.%s.IsPublic(p)", obj.Base)
	}
	o += fmt.Sprintf(publicfunc, obj.Name, createCase(public), sdefault)
	//IsPrivate
	sdefault = `return false`
	if obj.Base != "" {
		sdefault = fmt.Sprintf("return obj.%s.IsPrivate(p)", obj.Base)
	}
	o += fmt.Sprintf(privatefunc, obj.Name, createCase(private), sdefault)
	//IsSave
	sdefault = `return false`
	if obj.Base != "" {
		sdefault = fmt.Sprintf("return obj.%s.IsSave(p)", obj.Base)
	}
	o += fmt.Sprintf(savefunc, obj.Name, createCase(save), sdefault)

	if obj.Base == "" {
		//def
		return o + fmt.Sprintf(deffunc, obj.Name, obj.Name, obj.Name, obj.Name, obj.Name, obj.Name)
	} else {
		return o
	}

}

func (obj *Object) CreatePropertys() string {
	getset := `
//%s
func (obj *%s) Set%s(v %s) {
	obj.%s = v
%s
}

func (obj *%s) Get%s() %s {
	return obj.%s
}
`
	out := ""
	for _, p := range obj.Propertys {

		s := ""
		if p.Public != "" {
			s += fmt.Sprintf(`	obj.setModify("%s", v)
`, p.Name)
		}

		if p.Save == "true" {
			s += fmt.Sprintf(`	obj.setDirty("%s", v)`, p.Name)
		}

		out += fmt.Sprintf(getset, p.Comment, obj.Name, p.Name, p.Type, strings.ToLower(p.Name), s,
			obj.Name, p.Name, p.Type, strings.ToLower(p.Name))

	}

	return out
}

//创建表格部分
var (
	recorddef = `
//%s
type %s struct {
	maxRows int
	cols	int
	rows []%sRow
	dirty	bool
}
`
	rowdef = `
//%s行定义
type %sRow struct {
	%s}
`
	coldef = `	%s %s //%s
`
	initrecfunc = `
//初始化%s表
func (obj *%s)init%s() {
	obj.%s_r.maxRows = %d
	obj.%s_r.cols = %d
	obj.%s_r.rows = make([]%sRow, 0, %d)
}

//获取%s表
func (obj *%s)Get%s() *%s {
	return &obj.%s_r
}
`
	recinfofunc = `

//表格的容量
func (rec *%s) Cap() int {
	return rec.maxRows
}


//表格当前的行数
func (rec *%s) Rows() int {
	return len(rec.rows)
}

//获取列定义
func (rec *%s) ColTypes() ([]int, []string) {
	col := []int{%s}
	cols := []string{%s}
	return col, cols
}

//获取列数
func (rec *%s) Cols() int {
	return rec.cols
}

//脏标志
func (rec *%s) Dirty() bool {
	return rec.dirty
}

func (rec *%s) ClearDirty() {
	rec.dirty = false
}

`
	initAll = `
//初始化所有的表格
func (obj *%s)initRec() {
	%s
}

//获取某个表格
func (obj *%s)GetRec(rec string) interface{} {
	switch rec {
	%s
	default:
		return %s
	}
}
`
	getreccase = `
	case "%s":
		return &obj.%s_r
`
	recAddfunc = `
//增加一行,row=-1时,在表格最后面插入一行,否则在row处插入,返回-1插入失败,否则返回插入的行号
func (rec *%s)Add(row int,%s) int {
	add := -1

	if len(rec.rows) >= rec.maxRows {
		return add
	}

	r := %sRow{%s}

	if row == -1 {
		rec.rows = append(rec.rows, r)
		add = len(rec.rows) - 1
	} else {
		if row >= 0 && row < len(rec.rows) {
			rec.rows = append(rec.rows, %sRow{})
			copy(rec.rows[row+1:], rec.rows[row:])
			rec.rows[row] = r
			add = row
		} else {
			rec.rows = append(rec.rows, r)
			add = len(rec.rows) - 1
		}

	}
	if add != -1 {
		rec.dirty = true
	}
	return add
}
`
	getval = `	*%s = r.%s
`
	recGetfunc = `
//获取数据
func (rec *%s)Scan(row int,%s) bool {
	
	if row < 0 ||  row >= len(rec.rows) {
		return false
	}

	r := rec.rows[row]
	%s

	return true
}
`
	recDelfunc = `
//删除一行
func (rec *%s)Del(row int) {
	if row >= 0 {
		if len(rec.rows) > 1 {
			if row == 0 {
				copy(rec.rows[:], rec.rows[1:])
			} else {
				copy(rec.rows[row:], rec.rows[row+1:])
			}
			rec.rows = rec.rows[:len(rec.rows)-1]
			rec.dirty = true
		} else {
			rec.Clear()
		}
	}
}

//清空表格
func (rec *%s)Clear() {
	rec.rows = rec.rows[:0]
	rec.dirty = true
}
`

	recColGetSet = `
//设置%s
func (rec *%s)Set%s(row int, v %s) error {
	if row < 0 ||  row >= len(rec.rows) {
		return errors.New("row error")
	}

	rec.rows[row].%s = v
	rec.dirty = true
	return nil
}

//获取%s
func (rec *%s)Get%s(row int) (val %s, err error) {
	if row < 0 ||  row >= len(rec.rows) {
		err = errors.New("row error")
		return
	}

	val = rec.rows[row].%s
	return
}

`
	recSetCase = `
	case %d:
		val, ok := val.(%s)
		if ok {
			r.%s = val
		} else {
			return errors.New("val type mismatch")
		}
`
	recGetCase = `
	case %d:
		val = r.%s
`
	recGetSeter = `
//通过行列设置值
func (rec *%s)Set(row, col int, val interface{}) error {
	if row < 0 ||  row >= len(rec.rows) {
		return errors.New("row error")
	}

	if col < 0 || col >= %d {
		return errors.New("col error")
	}

	r := rec.rows[row]

	switch col {
	%s
	}

	rec.dirty = true
	return nil
}

//通过行列获取值
func (rec *%s)Get(row, col int) (val interface{}, err error) {
	if row < 0 ||  row >= len(rec.rows) {
		err = errors.New("row error")
		return
	}

	if col < 0 || col >= %d {
		err = errors.New("col error")
		return
	}

	r := rec.rows[row]

	switch col {
	%s	
	}

	return
}
`
)

func (obj *Object) createRecord(r Record) string {

	recname := fmt.Sprintf("%s%s", obj.Name, r.Name)
	columns := ""
	add := ""
	coltypes := ""
	coltypesStr := ""
	addval := ""
	getvals := ""
	getargs := ""
	colgetset := ""
	recset := ""
	recget := ""
	for n, c := range r.Columns {
		columns += fmt.Sprintf(coldef, strings.ToLower(c.Name), c.Type, c.Comment)
		add += fmt.Sprintf("%s %s,", strings.ToLower(c.Name), c.Type)
		addval += fmt.Sprintf("%s,", strings.ToLower(c.Name))
		coltypes += fmt.Sprintf("DT_%s,", strings.ToUpper(c.Type))
		coltypesStr += fmt.Sprintf(`"%s",`, c.Type)
		getvals += fmt.Sprintf(getval, strings.ToLower(c.Name), strings.ToLower(c.Name))
		getargs += fmt.Sprintf("%s *%s,", strings.ToLower(c.Name), c.Type)
		colgetset += fmt.Sprintf(recColGetSet, c.Comment,
			recname, c.Name, c.Type,
			strings.ToLower(c.Name),
			c.Comment,
			recname, c.Name, c.Type,
			strings.ToLower(c.Name))

		recset += fmt.Sprintf(recSetCase, n, c.Type, strings.ToLower(c.Name))
		recget += fmt.Sprintf(recGetCase, n, strings.ToLower(c.Name))

	}

	//表格定义部分
	rowstruct := fmt.Sprintf(rowdef, recname, recname, columns)

	rec := fmt.Sprintf(recorddef, recname, recname, recname)
	rec += rowstruct

	//表格信息获取部分
	rec += fmt.Sprintf(recinfofunc, recname,
		recname,
		recname, string([]byte(coltypes)[0:len(coltypes)-1]), string([]byte(coltypesStr)[0:len(coltypesStr)-1]),
		recname,
		recname,
		recname)

	//getseter
	rec += fmt.Sprintf(recGetSeter,
		recname,
		len(r.Columns),
		recset,
		recname,
		len(r.Columns),
		recget)

	rec += colgetset

	//增加一行
	rec += fmt.Sprintf(recAddfunc, recname, string([]byte(add)[0:len(add)-1]),
		recname, string([]byte(addval)[0:len(addval)-1]),
		recname)

	//获取一行
	rec += fmt.Sprintf(recGetfunc, recname, string([]byte(getargs)[0:len(getargs)-1]),
		getvals)

	//删除一行
	rec += fmt.Sprintf(recDelfunc, recname, recname)

	//初始化函数
	rec += fmt.Sprintf(initrecfunc, strings.ToLower(r.Name), obj.Name, recname,
		strings.ToLower(r.Name), r.Maxrows,
		strings.ToLower(r.Name), len(r.Columns),
		strings.ToLower(r.Name), recname, r.Maxrows,
		recname,
		obj.Name, recname, recname,
		strings.ToLower(r.Name))

	return rec
}

func (obj *Object) CreateRecords() string {

	recs := ""
	initrec := ""
	getrec := ""
	for _, r := range obj.Records {
		recs += obj.createRecord(r)
		initrec += fmt.Sprintf(`obj.init%s%s()
`, obj.Name, r.Name)
		getrec += fmt.Sprintf(getreccase, r.Name, strings.ToLower(r.Name))
	}

	getdefault := "nil"
	if obj.Base != "" {
		getdefault = fmt.Sprintf("obj.%s.GetRec(rec)", obj.Base)
	}

	recs += fmt.Sprintf(initAll, obj.Name,
		initrec,
		obj.Name, getrec,
		getdefault)
	return recs
}
